﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using UmlControlLibrary;

namespace UmlControlLibrary
{
    public class PropertyGroupingHelper
    {
        public delegate List<object> GetPropertyListDelegate(IEnumerable<object> properties);

        public Dictionary<string, GetPropertyListDelegate> RegisteredGroupers
        {
            get;
            set;
        }

        public delegate void GroupingFuncChangedHandler();
        public event GroupingFuncChangedHandler GroupingFuncChanged;

        private PropertyGroupingHelper.GetPropertyListDelegate _getPropertyListFunc;
        public PropertyGroupingHelper.GetPropertyListDelegate GetPropertyListFunc
        {
            get { return _getPropertyListFunc; }
            set {
                if (_getPropertyListFunc != value)
                {
                    _getPropertyListFunc = value;
                    if (GroupingFuncChanged != null)
                        GroupingFuncChanged();
                }
            }
        }

        private PropertyGroupingHelper()
        {
            RegisteredGroupers = new Dictionary<string, GetPropertyListDelegate>();
            RegisterGrouper("Name", GetPropertyListSortByName);
            RegisterGrouper("Modifier", GetPropertyListGroupByModifier);
            RegisterGrouper("Stereotype", GetPropertyListGroupByStereotype);
            RegisterGrouper("TypeName", GetPropertyListGroupByTypeName);
            GetPropertyListFunc = GetPropertyListSortByName;
        }

        public static void SetGrouper(GetPropertyListDelegate grouper)
        {
            GetInstance().GetPropertyListFunc = grouper;
        }

        public static void SetGrouper(string grouperName)
        {
            if (GetInstance().RegisteredGroupers.ContainsKey(grouperName))
                SetGrouper(GetInstance().RegisteredGroupers[grouperName]);
            else
                SetGrouper(GetInstance().GetPropertyListSortByName);
        }

        public void RegisterGrouper(string caption, GetPropertyListDelegate grouper)
        {
            RegisteredGroupers.Add(caption, grouper);
        }

        public static List<object> GetAsObjectList(IEnumerable<UmlMemberElement> properties)
        {
            List<object> objs = new List<object>();
            foreach (UmlMemberElement p in properties)
                objs.Add(p);
            return objs;
        }

        private static PropertyGroupingHelper _instance;
        public static PropertyGroupingHelper GetInstance()
        {
            if (_instance == null)
                _instance = new PropertyGroupingHelper();
            return _instance;
        }

        private static List<object> Group(IEnumerable<object> properties)
        {
            return GetInstance().GetPropertyListFunc(properties);
        }

        public static List<Object> Group(IEnumerable<UmlMemberElement> properties)
        {
            List<object> objs = GetAsObjectList(properties);
            objs = Group(objs);
            return objs;
        }


        public List<object> GetPropertyListNoGroup(IEnumerable<object> properties)
        {
            List<object> items = new List<object>();
            items.AddRange(properties);
            return items;
        }

        public List<object> GetPropertyListSortByName(IEnumerable<object> properties)
        {
            List<object> result = new List<object>();
            result.AddRange(properties.OrderBy(p => (p as UmlMemberElement).ElementName));
            return result;
        }

        public List<object> GetPropertyListGroupBy(IEnumerable<object> properties, Func<UmlMemberElement, string> GroupFunc)
        {
            List<object> result = new List<object>();
            IEnumerable<IGrouping<string, object>> items = properties.GroupBy(p => GroupFunc(p as UmlMemberElement), p => p);
            items = items.OrderBy(i => i.Key);
            foreach (IGrouping<string, object> group in items)
            {
                result.Add(group.Key);
                result.AddRange((IEnumerable<object>)group.OrderBy(p => (p as UmlMemberElement).ElementName));
            }
            return result;
        }

        private Dictionary<UmlModifier, string> _modifierTranslations = null;
        public List<object> GetPropertyListGroupByModifier(IEnumerable<object> properties)
        {
            if (_modifierTranslations == null)
            {
                List<UmlModifierItem> modifierItems = UmlModifierItem.GetPropertyModifiers();
                _modifierTranslations = new Dictionary<UmlModifier, string>();
                foreach (UmlModifierItem item in modifierItems) _modifierTranslations.Add(item.Modifier, item.Label);
            }
            return GetPropertyListGroupBy(properties, p => _modifierTranslations[p.Modifiers]);
        }

        public List<object> GetPropertyListGroupByTypeName(IEnumerable<object> properties)
        {
            return GetPropertyListGroupBy(properties, p => p.TypeName);
        }

        public List<object> GetPropertyListGroupByStereotype(IEnumerable<object> properties)
        {
            return GetPropertyListGroupBy(properties, p => p.StereoType);
        }
    }
}
